"""
EasyWebDB - 一个轻量级的Web数据管理库
支持HTML文件读写、JSON块数据操作和HTTP服务器
"""

import json
import os
import re
from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.parse
import threading
import time
from typing import Any, List, Dict, Union, Optional
from pathlib import Path

class EasyWebDB:
    """
    主类：提供HTML文件操作、JSON块数据操作和HTTP服务器功能
    """
    
    def __init__(self, json_file: str = "data.json", html_file: str = "index.html", 
                 port: int = 8086):
        """
        初始化EasyWebDB
        
        Args:
            json_file: JSON数据文件路径
            html_file: HTML文件路径
            port: HTTP服务器端口
        """
        # 确保文件名不为空
        self.json_file = json_file if json_file else "data.json"
        self.html_file = html_file if html_file else "index.html"
        self.port = port
        self.server = None
        self.server_thread = None
        
        # 确保文件存在
        self._ensure_files_exist()
    
    def _ensure_files_exist(self):
        """确保必要的文件存在"""
        # 确保JSON文件存在
        if self.json_file and not os.path.exists(self.json_file):
            try:
                with open(self.json_file, 'w', encoding='utf-8') as f:
                    f.write('[]')
            except Exception as e:
                print(f"创建JSON文件失败: {e}")
        
        # 确保HTML文件存在（如果不存在则创建默认页面）
        if self.html_file and not os.path.exists(self.html_file):
            try:
                self.write_html(self._get_default_html())
            except Exception as e:
                print(f"创建HTML文件失败: {e}")
    
    def _get_default_html(self) -> str:
        """获取默认HTML内容"""
        return '''<!DOCTYPE html><html><head><meta charset="UTF-8"><title>EasyWebDB</title><style>body{font-family:Arial,sans-serif;margin:40px;background:#f0f0f0}h1{color:#333}.container{max-width:800px;margin:0 auto;background:white;padding:20px;border-radius:10px;box-shadow:0 2px 10px rgba(0,0,0,0.1)}.data-item{border:1px solid #ddd;padding:10px;margin:10px 0;border-radius:5px;background:#fafafa}pre{background:#f8f9fa;padding:10px;border-radius:5px;overflow:auto}</style></head><body><div class="container"><h1>EasyWebDB数据管理</h1><p>这是一个默认页面，您可以使用write_html方法重写此页面。</p><div id="dataDisplay"></div></div><script>fetch('/api/data').then(r=>r.json()).then(data=>{const container=document.getElementById('dataDisplay');if(data&&data.length>0){container.innerHTML=data.map((item,i)=>`<div class="data-item"><h3>数据块${i}</h3><pre>${JSON.stringify(item,null,2)}</pre></div>`).join('');}else{container.innerHTML='<p>暂无数据</p>';}});</script></body></html>'''
    
    # ==================== HTML文件操作 ====================
    
    def read_html(self, file_path: Optional[str] = None) -> str:
        """
        读取HTML文件内容
        
        Args:
            file_path: 文件路径，如果为None则使用实例的html_file
            
        Returns:
            HTML文件内容
        """
        path = file_path or self.html_file
        if not path:
            return ""
        
        try:
            with open(path, 'r', encoding='utf-8') as f:
                return f.read()
        except FileNotFoundError:
            return ""
        except Exception as e:
            print(f"读取HTML文件失败: {e}")
            return ""
    
    def write_html(self, content: str, file_path: Optional[str] = None) -> bool:
        """
        写入HTML文件内容（重写整个文件）
        
        Args:
            content: HTML内容（不需要缩进或换行）
            file_path: 文件路径，如果为None则使用实例的html_file
            
        Returns:
            成功返回True，失败返回False
        """
        path = file_path or self.html_file
        if not path:
            return False
        
        try:
            # 获取目录路径，如果目录名为空，表示当前目录，不需要创建
            dir_name = os.path.dirname(path)
            if dir_name:  # 只有当目录名非空时才创建
                os.makedirs(dir_name, exist_ok=True)
            
            # 写入文件
            with open(path, 'w', encoding='utf-8') as f:
                f.write(content)
            return True
        except Exception as e:
            print(f"写入HTML文件失败: {e}")
            return False
    
    # ==================== JSON数据操作 ====================
    
    def _parse_blocks(self, content: str) -> List[Dict[str, Any]]:
        """
        解析JSON块数据
        
        Args:
            content: JSON文件内容
            
        Returns:
            解析后的块列表
        """
        blocks = []
        
        # 去除空白字符
        content = content.strip()
        if not content:
            return []
        
        # 如果内容以[]包裹，则解析为数组
        if content.startswith('[') and content.endswith(']'):
            try:
                return json.loads(content)
            except:
                pass
        
        # 否则按块解析
        # 查找所有{...}块
        pattern = r'\{[^{}]*\}|\{[^{}]*\{[^{}]*\}[^{}]*\}'
        matches = re.findall(pattern, content)
        
        for match in matches:
            try:
                # 尝试解析为JSON
                block = json.loads(match)
                blocks.append(block)
            except json.JSONDecodeError:
                # 如果不是标准JSON，尝试作为JavaScript对象解析
                try:
                    # 将JavaScript格式转换为JSON格式
                    cleaned = match.replace("'", '"').replace(';', ',')
                    # 修复键值对
                    cleaned = re.sub(r'(\w+):', r'"\1":', cleaned)
                    # 确保最后一个逗号被移除
                    if cleaned.endswith(',}'):
                        cleaned = cleaned[:-2] + '}'
                    block = json.loads(cleaned)
                    blocks.append(block)
                except:
                    # 如果还是失败，则跳过这个块
                    continue
        
        return blocks
    
    def _format_blocks(self, blocks: List[Dict[str, Any]]) -> str:
        """
        将块列表格式化为字符串
        
        Args:
            blocks: 块列表
            
        Returns:
            格式化后的字符串
        """
        if not blocks:
            return "[]"
        
        # 使用JSON格式，但每个块占一行
        result = "[\n"
        for i, block in enumerate(blocks):
            result += json.dumps(block, ensure_ascii=False)
            if i < len(blocks) - 1:
                result += ",\n"
        result += "\n]"
        return result
    
    def read_json_blocks(self, file_path: Optional[str] = None) -> List[Dict[str, Any]]:
        """
        读取JSON文件中的所有块
        
        Args:
            file_path: 文件路径，如果为None则使用实例的json_file
            
        Returns:
            块列表
        """
        path = file_path or self.json_file
        if not path:
            return []
        
        try:
            with open(path, 'r', encoding='utf-8') as f:
                content = f.read()
                return self._parse_blocks(content)
        except FileNotFoundError:
            return []
        except Exception as e:
            print(f"读取JSON文件失败: {e}")
            return []
    
    def write_json_blocks(self, blocks: List[Dict[str, Any]], 
                         file_path: Optional[str] = None) -> bool:
        """
        写入JSON块数据
        
        Args:
            blocks: 块列表
            file_path: 文件路径，如果为None则使用实例的json_file
            
        Returns:
            成功返回True，失败返回False
        """
        path = file_path or self.json_file
        if not path:
            return False
        
        try:
            # 获取目录路径，如果目录名为空，表示当前目录，不需要创建
            dir_name = os.path.dirname(path)
            if dir_name:  # 只有当目录名非空时才创建
                os.makedirs(dir_name, exist_ok=True)
            
            # 格式化并写入
            content = self._format_blocks(blocks)
            with open(path, 'w', encoding='utf-8') as f:
                f.write(content)
            return True
        except Exception as e:
            print(f"写入JSON文件失败: {e}")
            return False
    
    def _resolve_path(self, block: Any, path: str) -> Any:
        """
        根据路径解析数据
        
        Args:
            block: 当前数据块
            path: 路径字符串，如 '0.0' 或 '1.name'
            
        Returns:
            解析出的数据
        """
        if not path:
            return block
        
        parts = path.split('.')
        current = block
        
        for part in parts:
            # 尝试作为索引
            if part.isdigit():
                index = int(part)
                if isinstance(current, list) and 0 <= index < len(current):
                    current = current[index]
                else:
                    raise KeyError(f"索引{index}超出范围或类型错误")
            else:
                # 作为键名
                if isinstance(current, dict) and part in current:
                    current = current[part]
                else:
                    raise KeyError(f"键'{part}'不存在")
        
        return current
    
    def query_json(self, path: str, file_path: Optional[str] = None) -> Any:
        """
        查询JSON数据
        
        Args:
            path: 查询路径，如 '0'（第一个块）、'0.name'（第一个块的name属性）
            file_path: 文件路径，如果为None则使用实例的json_file
            
        Returns:
            查询到的数据
        """
        blocks = self.read_json_blocks(file_path)
        
        if not blocks:
            raise ValueError("JSON文件为空")
        
        # 解析块索引
        path_parts = path.split('.', 1)
        block_index = path_parts[0]
        
        if not block_index.isdigit():
            raise ValueError(f"路径必须以数字开头: {path}")
        
        index = int(block_index)
        if index >= len(blocks):
            raise ValueError(f"块索引{index}超出范围")
        
        block = blocks[index]
        
        # 如果有子路径，则继续解析
        if len(path_parts) > 1:
            return self._resolve_path(block, path_parts[1])
        else:
            return block
    
    def update_json(self, path: str, value: Any, 
                   file_path: Optional[str] = None) -> bool:
        """
        更新JSON数据
        
        Args:
            path: 更新路径
            value: 新值
            file_path: 文件路径，如果为None则使用实例的json_file
            
        Returns:
            成功返回True，失败返回False
        """
        blocks = self.read_json_blocks(file_path)
        
        if not blocks:
            # 如果文件为空且路径是'0'，则创建第一个块
            if path == '0':
                blocks = [value]
                return self.write_json_blocks(blocks, file_path)
            else:
                raise ValueError("JSON文件为空，无法更新非0位置")
        
        # 解析路径
        path_parts = path.split('.')
        block_index = int(path_parts[0])
        
        if block_index >= len(blocks):
            # 如果索引超出范围，扩展列表
            for _ in range(block_index - len(blocks) + 1):
                blocks.append({})
        
        if len(path_parts) == 1:
            # 更新整个块
            blocks[block_index] = value
        else:
            # 更新块内的特定字段
            block = blocks[block_index]
            # 创建或获取深层路径
            current = block
            for i, part in enumerate(path_parts[1:-1]):
                next_part = path_parts[i+2]
                
                # 确定下一部分的类型
                if next_part.isdigit():
                    # 下一部分是数字，当前应该是列表
                    if part not in current:
                        current[part] = []
                    elif not isinstance(current[part], list):
                        current[part] = []
                else:
                    # 下一部分是字符串，当前应该是字典
                    if part not in current:
                        current[part] = {}
                    elif not isinstance(current[part], dict):
                        current[part] = {}
                
                current = current[part]
            
            # 设置最终值
            last_part = path_parts[-1]
            if isinstance(current, dict):
                current[last_part] = value
            elif isinstance(current, list) and last_part.isdigit():
                index = int(last_part)
                # 确保列表足够长
                while len(current) <= index:
                    current.append(None)
                current[index] = value
        
        return self.write_json_blocks(blocks, file_path)
    
    def delete_json(self, path: str, file_path: Optional[str] = None) -> bool:
        """
        删除JSON数据
        
        Args:
            path: 删除路径
            file_path: 文件路径，如果为None则使用实例的json_file
            
        Returns:
            成功返回True，失败返回False
        """
        blocks = self.read_json_blocks(file_path)
        
        if not blocks:
            return False
        
        # 解析路径
        path_parts = path.split('.')
        block_index = int(path_parts[0])
        
        if block_index >= len(blocks):
            return False
        
        if len(path_parts) == 1:
            # 删除整个块
            blocks.pop(block_index)
        else:
            # 删除块内的特定字段
            block = blocks[block_index]
            current = block
            
            # 导航到父级
            for part in path_parts[1:-1]:
                if isinstance(current, dict) and part in current:
                    current = current[part]
                elif isinstance(current, list) and part.isdigit():
                    index = int(part)
                    if 0 <= index < len(current):
                        current = current[index]
                    else:
                        return False
                else:
                    return False
            
            # 删除最终字段
            last_part = path_parts[-1]
            if isinstance(current, dict) and last_part in current:
                del current[last_part]
            elif isinstance(current, list) and last_part.isdigit():
                index = int(last_part)
                if 0 <= index < len(current):
                    current.pop(index)
            else:
                return False
        
        return self.write_json_blocks(blocks, file_path)
    
    def insert_json(self, value: Any, position: Optional[int] = None,
                   file_path: Optional[str] = None) -> bool:
        """
        插入JSON数据
        
        Args:
            value: 要插入的值
            position: 插入位置，如果为None则插入到末尾
            file_path: 文件路径，如果为None则使用实例的json_file
            
        Returns:
            成功返回True，失败返回False
        """
        blocks = self.read_json_blocks(file_path)
        
        if position is None:
            position = len(blocks)
        
        if position > len(blocks):
            # 填充空白位置
            for _ in range(position - len(blocks)):
                blocks.append({})
        
        blocks.insert(position, value)
        return self.write_json_blocks(blocks, file_path)
    
    # ==================== HTTP服务器 ====================
    
    class _RequestHandler(BaseHTTPRequestHandler):
        """HTTP请求处理器"""
        
        def __init__(self, *args, **kwargs):
            self.db = kwargs.pop('db_instance')
            super().__init__(*args, **kwargs)
        
        def _set_headers(self, status_code=200, content_type='application/json'):
            """设置HTTP响应头"""
            self.send_response(status_code)
            self.send_header('Content-type', content_type)
            self.send_header('Access-Control-Allow-Origin', '*')
            self.send_header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
            self.send_header('Access-Control-Allow-Headers', 'Content-Type')
            self.end_headers()
        
        def do_OPTIONS(self):
            """处理预检请求"""
            self._set_headers(200)
        
        def do_GET(self):
            """处理GET请求"""
            parsed_path = urllib.parse.urlparse(self.path)
            
            if parsed_path.path == '/':
                # 返回HTML页面
                self._serve_html()
            elif parsed_path.path == '/api/data':
                # 返回所有JSON数据
                self._get_all_data()
            elif parsed_path.path.startswith('/api/data/'):
                # 查询特定数据
                self._query_data(parsed_path.path)
            else:
                self._set_headers(404)
                self.wfile.write(json.dumps({'error': 'Not found'}).encode())
        
        def do_POST(self):
            """处理POST请求"""
            parsed_path = urllib.parse.urlparse(self.path)
            
            if parsed_path.path == '/api/data':
                # 插入新数据
                content_length = int(self.headers['Content-Length'])
                post_data = self.rfile.read(content_length)
                
                try:
                    data = json.loads(post_data.decode('utf-8'))
                    
                    # 获取位置参数
                    query = urllib.parse.parse_qs(parsed_path.query)
                    position = query.get('position', [None])[0]
                    
                    if position is not None:
                        position = int(position)
                    
                    success = self.db.insert_json(data, position)
                    
                    if success:
                        self._set_headers(201)
                        self.wfile.write(json.dumps({'success': True}).encode())
                    else:
                        self._set_headers(500)
                        self.wfile.write(json.dumps({'error': 'Insert failed'}).encode())
                        
                except Exception as e:
                    self._set_headers(400)
                    self.wfile.write(json.dumps({'error': str(e)}).encode())
            else:
                self._set_headers(404)
        
        def do_PUT(self):
            """处理PUT请求"""
            parsed_path = urllib.parse.urlparse(self.path)
            
            if parsed_path.path.startswith('/api/data/'):
                try:
                    # 解析路径
                    path = parsed_path.path[10:]  # 移除'/api/data/'
                    
                    content_length = int(self.headers['Content-Length'])
                    put_data = self.rfile.read(content_length)
                    data = json.loads(put_data.decode('utf-8'))
                    
                    success = self.db.update_json(path, data)
                    
                    if success:
                        self._set_headers(200)
                        self.wfile.write(json.dumps({'success': True}).encode())
                    else:
                        self._set_headers(500)
                        self.wfile.write(json.dumps({'error': 'Update failed'}).encode())
                        
                except Exception as e:
                    self._set_headers(400)
                    self.wfile.write(json.dumps({'error': str(e)}).encode())
            else:
                self._set_headers(404)
        
        def do_DELETE(self):
            """处理DELETE请求"""
            parsed_path = urllib.parse.urlparse(self.path)
            
            if parsed_path.path.startswith('/api/data/'):
                try:
                    path = parsed_path.path[10:]  # 移除'/api/data/'
                    
                    success = self.db.delete_json(path)
                    
                    if success:
                        self._set_headers(200)
                        self.wfile.write(json.dumps({'success': True}).encode())
                    else:
                        self._set_headers(500)
                        self.wfile.write(json.dumps({'error': 'Delete failed'}).encode())
                        
                except Exception as e:
                    self._set_headers(400)
                    self.wfile.write(json.dumps({'error': str(e)}).encode())
            else:
                self._set_headers(404)
        
        def _serve_html(self):
            """提供HTML页面"""
            try:
                html_content = self.db.read_html()
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write(html_content.encode())
            except Exception as e:
                self._set_headers(500)
                self.wfile.write(json.dumps({'error': str(e)}).encode())
        
        def _get_all_data(self):
            """获取所有数据"""
            try:
                data = self.db.read_json_blocks()
                self._set_headers(200)
                self.wfile.write(json.dumps(data).encode())
            except Exception as e:
                self._set_headers(500)
                self.wfile.write(json.dumps({'error': str(e)}).encode())
        
        def _query_data(self, path):
            """查询特定数据"""
            try:
                # 提取查询路径
                query_path = path[10:]  # 移除'/api/data/'
                data = self.db.query_json(query_path)
                self._set_headers(200)
                self.wfile.write(json.dumps(data).encode())
            except Exception as e:
                self._set_headers(400)
                self.wfile.write(json.dumps({'error': str(e)}).encode())
        
        def log_message(self, format, *args):
            """重写日志方法，减少输出"""
            pass
    
    def start_server(self, port: Optional[int] = None, background: bool = False):
        """
        启动HTTP服务器
        
        Args:
            port: 端口号，如果为None则使用实例的port
            background: 是否在后台运行
        """
        server_port = port or self.port
        
        def run_server():
            server_address = ('', server_port)
            handler = lambda *args, **kwargs: self._RequestHandler(*args, **kwargs, db_instance=self)
            self.server = HTTPServer(server_address, handler)
            
            print(f"EasyWebDB HTTP服务器启动在 http://localhost:{server_port}")
            print("API端点:")
            print(f"  GET  /              - 查看HTML页面")
            print(f"  GET  /api/data      - 获取所有JSON数据")
            print(f"  GET  /api/data/path - 查询特定数据 (如 /api/data/0)")
            print(f"  POST /api/data      - 插入新数据")
            print(f"  POST /api/data?position=n - 在指定位置插入数据")
            print(f"  PUT  /api/data/path - 更新数据")
            print(f"  DELETE /api/data/path - 删除数据")
            
            try:
                self.server.serve_forever()
            except KeyboardInterrupt:
                print("\n服务器已停止")
        
        if background:
            self.server_thread = threading.Thread(target=run_server, daemon=True)
            self.server_thread.start()
        else:
            run_server()
    
    def stop_server(self):
        """停止HTTP服务器"""
        if self.server:
            self.server.shutdown()
            print("HTTP服务器已停止")


# ==================== 使用示例 ====================

if __name__ == "__main__":
    # 创建实例
    db = EasyWebDB(json_file="test_data.json", html_file="test_page.html", port=8086)
    
    # 示例1：读写HTML文件
    print("=== 示例1: HTML文件操作 ===")
    
    # 写入HTML内容（不需要缩进和换行）
    html_content = '''<!DOCTYPE html><html><head><meta charset="UTF-8"><title>我的页面</title><style>body{font-family:Arial;margin:20px;}</style></head><body><h1>欢迎使用EasyWebDB</h1><div id="content"></div><script>fetch('/api/data').then(r=>r.json()).then(data=>{document.getElementById('content').innerHTML='<p>数据块数量：'+data.length+'</p>'+data.map((d,i)=>'<div><h3>块'+i+'</h3><pre>'+JSON.stringify(d,null,2)+'</pre></div>').join('');});</script></body></html>'''
    db.write_html(html_content)
    print("HTML文件已写入")
    
    # 读取HTML文件
    content = db.read_html()
    print(f"HTML文件内容长度: {len(content)} 字符")
    
    # 示例2：JSON数据操作
    print("\n=== 示例2: JSON数据操作 ===")
    
    # 清空并写入示例数据
    sample_data = [
        {"x": 2, "y": 3, "z": 4, "nested": {"a": 1, "b": 2}},
        {"name": "test", "value": 100, "list": [10, 20, 30]},
        {"status": "active", "data": {"count": 5, "items": ["apple", "banana"]}}
    ]
    db.write_json_blocks(sample_data)
    print("JSON数据已写入")
    
    # 读取所有块
    blocks = db.read_json_blocks()
    print(f"读取到 {len(blocks)} 个数据块")
    
    # 查询数据
    print("\n查询示例:")
    
    # 查询第一个块
    block0 = db.query_json('0')
    print(f"块0: {block0}")
    
    # 查询第一个块的x属性
    x_value = db.query_json('0.x')
    print(f"块0.x: {x_value}")
    
    # 查询嵌套数据
    nested_a = db.query_json('0.nested.a')
    print(f"块0.nested.a: {nested_a}")
    
    # 查询列表元素
    list_item = db.query_json('1.list.0')
    print(f"块1.list.0: {list_item}")
    
    # 更新数据
    print("\n更新示例:")
    
    # 更新第一个块的x属性
    db.update_json('0.x', 999)
    print("更新 0.x = 999")
    
    # 更新嵌套数据
    db.update_json('0.nested.a', 888)
    print("更新 0.nested.a = 888")
    
    # 在嵌套结构中创建新字段
    db.update_json('0.nested.c', 777)
    print("创建 0.nested.c = 777")
    
    # 创建新块
    db.update_json('3', {"new": "block", "id": 100})
    print("创建新块3")
    
    # 删除数据
    print("\n删除示例:")
    
    # 删除属性
    db.delete_json('0.y')
    print("删除 0.y")
    
    # 删除块
    db.delete_json('2')
    print("删除块2")
    
    # 插入数据
    print("\n插入示例:")
    
    # 在指定位置插入
    db.insert_json({"inserted": "data", "at": "position 1"}, position=1)
    print("在位置1插入新块")
    
    # 在末尾插入
    db.insert_json({"inserted": "at end"})
    print("在末尾插入新块")
    
    # 显示最终数据
    final_data = db.read_json_blocks()
    print(f"\n最终数据块数量: {len(final_data)}")
    for i, block in enumerate(final_data):
        print(f"块{i}: {block}")
    
    # 示例3：启动HTTP服务器
    print("\n=== 示例3: HTTP服务器 ===")
    print("启动HTTP服务器...")
    print("按 Ctrl+C 停止服务器")
    
    # 在后台启动服务器
    db.start_server(background=False)
